﻿using System;
using System.IO;
using System.Net;

namespace HashFoo.Core
{
    /// <summary>
    /// Allows different web client infrastructures to be used.
    /// </summary>
    public interface IWebClient
    {
        /// <summary>
        /// Headers to be applied to all requests.
        /// </summary>
        WebHeaderCollection DefaultHeaders { get; }

        /// <summary>
        /// Performs a web request that uploads data as a string.  Any server response is returned as a string.
        /// </summary>
        /// <param name="uri">The uri to call</param>
        /// <param name="data">The data to upload</param>
        /// <param name="successCallback">Callback for successful completion</param>
        /// <param name="errorCallback">Callback if there is an error</param>
        /// <param name="cancelCallback">Callback if the operation is canceled</param>
        /// <param name="method">HTTP method override.</param>
        /// <returns>The operation, useful to cancel if needed.</returns>
        IWebClientOperation UploadStringAsync(
            Uri uri, string data, 
            Action<IWebResultString> successCallback = null, 
            Action<WebRequestError> errorCallback = null, 
            Action cancelCallback = null, 
            string method = null);

        /// <summary>
        /// Performs a web request that uploads data from a stream.  Any server response is returned as a string.
        /// </summary>
        /// <param name="uri">The uri to call</param>
        /// <param name="data">The data to upload</param>
        /// <param name="successCallback">Callback for successful completion</param>
        /// <param name="errorCallback">Callback if there is an error</param>
        /// <param name="cancelCallback">Callback if the operation is canceled</param>
        /// <param name="progressCallback">Callback for progress updates of the upload</param>
        /// <param name="method">HTTP method override.</param>
        /// <returns>The operation, useful to cancel if needed.</returns>
        IWebClientOperation UploadStreamAsync(
            Uri uri, 
            Stream data, 
            Action<IWebResultString> successCallback = null, 
            Action<WebRequestError> errorCallback = null, 
            Action cancelCallback = null, 
            Action<ProgressEventArgs> progressCallback = null,
            string method = null);

        /// <summary>
        /// Performs a web request that uploads data from a byte array.  Any server response is returned as a string.
        /// </summary>
        /// <param name="uri">The uri to call</param>
        /// <param name="data">The data to upload</param>
        /// <param name="successCallback">Callback for successful completion</param>
        /// <param name="errorCallback">Callback if there is an error</param>
        /// <param name="cancelCallback">Callback if the operation is canceled</param>
        /// <param name="progressCallback">Callback for progress updates of the upload</param>
        /// <param name="method">HTTP method override.</param>
        /// <returns>The operation, useful to cancel if needed.</returns>
        IWebClientOperation UploadBytesAsync(
            Uri uri,
            byte[] data,
            Action<IWebResultString> successCallback = null,
            Action<WebRequestError> errorCallback = null,
            Action cancelCallback = null,
            Action<ProgressEventArgs> progressCallback = null,
            string method = null);

        /// <summary>
        /// Perform a web request and return the result as a string.
        /// </summary>
        /// <param name="uri">The uri to call</param>
        /// <param name="successCallback">Callback for successful completion</param>
        /// <param name="errorCallback">Callback if there is an error</param>
        /// <param name="cancelCallback">Callback if the operation is canceled</param>
        /// <param name="progressCallback">Callback for progress updates</param>
        /// <param name="method">HTTP method override.</param>
        /// <returns>The operation, useful to cancel if needed.</returns>
        IWebClientOperation DownloadStringAsync(
            Uri uri, Action<IWebResultString> successCallback,
            Action<WebRequestError> errorCallback = null,
            Action cancelCallback = null,
            Action<ProgressEventArgs> progressCallback = null,
            string method = null);

        /// <summary>
        /// Perform a web request and return the result as the raw response stream.
        /// </summary>
        /// <param name="uri">The uri to call</param>
        /// <param name="successCallback">Callback for successful completion</param>
        /// <param name="errorCallback">Callback if there is an error</param>
        /// <param name="cancelCallback">Callback if the operation is canceled</param>
        /// <param name="progressCallback">Callback for progress updates.</param>
        /// <param name="method">HTTP method override.</param>
        /// <param name="buffer">
        ///   If <c>true</c>, the network stream will be downloaded completely, then wrapped in a memory stream.
        ///   Else, the network stream will be returned.  Default to true.
        /// </param>
        /// <returns>The operation, useful to cancel if needed.</returns>
        /// <remarks>
        /// If the stream is not buffered, the <paramref name="progressCallback"/> will not be invoked.
        /// Buffering should probably be turned off for very large files (>10MBs).
        /// </remarks>
        IWebClientOperation DownloadStreamAsync(
            Uri uri,
            Action<IWebResultStream> successCallback,
            Action<WebRequestError> errorCallback = null,
            Action cancelCallback = null,
            Action<ProgressEventArgs> progressCallback = null, 
            string method = null,
            bool buffer = true);
    }
}